///*
// * Note from shayner: This is an example taken from the internet at
// * http://www.devmaster.net/articles/openal-tutorials/lesson8.php
// * Use it and learn, boy! 
// */
//#include <string>
//#include <iostream>
//using namespace std;
// 
//#include <AL/al.h>
//#include <AL/alc.h>
//#include <AL/alut.h>
//#include <ogg/ogg.h>
//#include <vorbis/codec.h>
//#include <vorbis/vorbisenc.h>
//#include <vorbis/vorbisfile.h>
//
//#define BUFFER_SIZE (4096 * 16)
//
//class ogg_stream
//{
//    public:
// 
//        void open(string path); // obtain a handle to the file
//        void release();         // release the file handle
//        void display();         // display some info on the Ogg
//        bool playback();        // play the Ogg stream
//        bool playing();         // check if the source is playing
//        bool update();          // update the stream if necessary
// 
//    protected:
// 
//        bool stream(ALuint buffer);   // reloads a buffer
//        void empty();                 // empties the queue
//        void check();                 // checks OpenAL error state
//        string errorString(int code); // stringify an error code
//    private:
// 
//        FILE*           oggFile;       // file handle
//        OggVorbis_File  oggStream;     // stream handle
//        vorbis_info*    vorbisInfo;    // some formatting data
//        vorbis_comment* vorbisComment; // user comments
// 
//        ALuint buffers[2]; // front and back buffers
//        ALuint source;     // audio source
//        ALenum format;     // internal format
//};
//
//void ogg_stream::open(string path)
//{
//    int result;
//    
//    if(!(oggFile = fopen(path.c_str(), "rb")))
//        throw string("Could not open Ogg file.");
// 
//    if((result = ov_open(oggFile, &oggStream, NULL, 0)) < 0)
//    {
//        fclose(oggFile);
// 
//        throw string("Could not open Ogg stream. ") + errorString(result);
//    }
//
//    vorbisInfo = ov_info(&oggStream, -1);
//    vorbisComment = ov_comment(&oggStream, -1);
// 
//    if(vorbisInfo->channels == 1)
//        format = AL_FORMAT_MONO16;
//    else
//        format = AL_FORMAT_STEREO16;
//
//    alGenBuffers(2, buffers);
//    check();
//    alGenSources(1, &source);
//    check();
//    
//    alSource3f(source, AL_POSITION,        0.0, 0.0, 0.0);
//    alSource3f(source, AL_VELOCITY,        0.0, 0.0, 0.0);
//    alSource3f(source, AL_DIRECTION,       0.0, 0.0, 0.0);
//    alSourcef (source, AL_ROLLOFF_FACTOR,  0.0          );
//    alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE      );
//}
//
//void ogg_stream::release()
//{
//    alSourceStop(source);
//    empty();
//    alDeleteSources(1, &source);
//    check();
//    alDeleteBuffers(1, buffers);
//    check();
// 
//    ov_clear(&oggStream);
//}
//
//void ogg_stream::display()
//{
//    cout
//        << "version         " << vorbisInfo->version         << "\n"
//        << "channels        " << vorbisInfo->channels        << "\n"
//        << "rate (hz)       " << vorbisInfo->rate            << "\n"
//        << "bitrate upper   " << vorbisInfo->bitrate_upper   << "\n"
//        << "bitrate nominal " << vorbisInfo->bitrate_nominal << "\n"
//        << "bitrate lower   " << vorbisInfo->bitrate_lower   << "\n"
//        << "bitrate window  " << vorbisInfo->bitrate_window  << "\n"
//        << "\n"
//        << "vendor " << vorbisComment->vendor << "\n";
//        
//    for(int i = 0; i < vorbisComment->comments; i++)
//        cout << "   " << vorbisComment->user_comments[i] << "\n";
//        
//    cout << endl;
//}
//
//bool ogg_stream::playback()
//{
//    if(playing())
//        return true;
//        
//    if(!stream(buffers[0]))
//        return false;
// 
//    if(!stream(buffers[1]))
//        return false;
//    
//    alSourceQueueBuffers(source, 2, buffers);
//    alSourcePlay(source);
//    
//    return true;
//}
//
//bool ogg_stream::playing()
//{
//    ALenum state;
//    
//    alGetSourcei(source, AL_SOURCE_STATE, &state);
//    
//    return (state == AL_PLAYING);
//}
//
//bool ogg_stream::update()
//{
//    int processed;
//    bool active = true;
// 
//    alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
// 
//    while(processed--)
//    {
//        ALuint buffer;
//        
//        alSourceUnqueueBuffers(source, 1, &buffer);
//        check();
// 
//        active = stream(buffer);
// 
//        alSourceQueueBuffers(source, 1, &buffer);
//        check();
//    }
// 
//    return active;
//}
//
//bool ogg_stream::stream(ALuint buffer)
//{
//    char data[BUFFER_SIZE];
//    int  size = 0;
//    int  section;
//    int  result;
// 
//    while(size < BUFFER_SIZE)
//    {
//        result = ov_read(&oggStream, data + size, BUFFER_SIZE - size, 0, 2, 1, & section);
//    
//        if(result > 0)
//            size += result;
//        else
//            if(result < 0)
//                throw errorString(result);
//            else
//                break;
//    }
//    
//    if(size == 0)
//        return false;
// 
//    alBufferData(buffer, format, data, size, vorbisInfo->rate);
//    check();
// 
//    return true;
//}
//
//void ogg_stream::empty()
//{
//    int queued;
//    
//    alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
//    
//    while(queued--)
//    {
//        ALuint buffer;
//    
//        alSourceUnqueueBuffers(source, 1, &buffer);
//        check();
//    }
//}
//
//void ogg_stream::check()
//{
//    int error = alGetError();
// 
//    if(error != AL_NO_ERROR)
//        throw string("OpenAL error was raised.");
//}
//
//string ogg_stream::errorString(int code)
//{
//    switch(code)
//    {
//        case OV_EREAD:
//            return string("Read from media.");
//        case OV_ENOTVORBIS:
//            return string("Not Vorbis data.");
//        case OV_EVERSION:
//            return string("Vorbis version mismatch.");
//        case OV_EBADHEADER:
//            return string("Invalid Vorbis header.");
//        case OV_EFAULT:
//            return string("Internal logic fault (bug or heap/stack corruption.");
//        default:
//            return string("Unknown Ogg error.");
//    }
//}
//
//int main(int argc, char **argv) {
//    ogg_stream ogg;
// 
//    alutInit(&argc, argv);
//    
//    try
//    {
//    	if(argc == 2)
//    	{
//    		cout << "Attempting to play " << argv[1] << endl;
//            ogg.open(argv[1]);
//    	}
//    	else
//    	{
//    		cout << "Attempting to play audio.ogg" << endl;
//            ogg.open("audio.ogg");
//    	}
//
// 
//        ogg.display();
//        
//        if(!ogg.playback())
//            throw string("Ogg refused to play.");
//                    
//        while(ogg.update())
//        {
//            if(!ogg.playing())
//            {
//                if(!ogg.playback())
//                    throw string("Ogg abruptly stopped.");
//                else
//                    cout << "Ogg stream was interrupted.\n";
//            }
//        }
//                    
//        cout << "Program normal termination.";
//        cin.get();
//    }
//    catch(string error)
//    {
//        cout << error;
//        cin.get();
//    }
//
//    ogg.release();
//
//    alutExit();
//
//    return EXIT_SUCCESS;
//}
